﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ApplLogic.ApplDbMediators;
using AlgoImpl;
using ApplLogic.ApplClasses;
using ApplLogic.ApplToAlgoConvertor;
using ApplLogic.Exceptions;

namespace ApplLogic.LogicalServices
{
    public class ApplAlgoExecuter
    {
        private ShiftOrganizorManager m_AlgoManager = null;

        public ApplAlgoExecuter() { }

        public void RunAlgo(DateTime startTime, DateTime endTime)
        {
            removeResultsFromWeek(startTime, endTime);
            executeAlgo(startTime, endTime);
        }

        private void removeResultsFromWeek(DateTime startTime, DateTime endTime)
        {
            const bool k_DeleteAll = true;
            ApplDbResultMediator.Instance.DeleteAllResultsInTimeRange(startTime, endTime, k_DeleteAll);
        }

        private void executeAlgo(DateTime startTime, DateTime endTime)
        {
            SharedData.Instance.Clear();
            setAllWorkersAndShiftsToAlgoImpl(startTime, endTime);
            FinalResultHolder.Instance.Clear();
            ShiftRequests shiftRequests = createShiftRequest(startTime, endTime);
            m_AlgoManager = new ShiftOrganizorManager(shiftRequests);
            m_AlgoManager.OrganizeWorkersToShifts();
            saveResultsToDb();
            ApplStatHandler statHandler = new ApplStatHandler(startTime, endTime, shiftRequests);
            ApplDbWorkerStatMediator.Instance.DeleteStatInDateRangeForAllWorkers(startTime, endTime, true);
            statHandler.SaveStatForWeek();
        }

        private void saveResultsToDb()
        {
            foreach (string workerId in FinalResultHolder.Instance.FinalResultOfSCModul.Keys)
            {
                foreach (ShiftResult singleAssigment in FinalResultHolder.Instance.GetShiftResultOfWorker(workerId))
                {
                    ApplSingleResult resultToAdd = new ApplSingleResult()
                    {
                        Step = ApplAlgoObjectConvertor.CreateApplResultFromAlgoResult(singleAssigment.Step),
                        ApplWorker = ApplDbWorkerMediator.Instance.GetWorker(workerId),
                        ApplShift = ApplDbShiftMediator.Instance.GetShift(singleAssigment.Id)
                        
                    };
                    ApplDbResultMediator.Instance.AddResultShiftToWorkerWithStep(resultToAdd, true);
                }
            }
            
        }

        private ShiftRequests createShiftRequest(DateTime startTime, DateTime endTime)
        {
            ShiftRequests requests = new ShiftRequests();
            List<string> workersFromDb = ApplDbWorkerMediator.Instance.GetAllWorkersIds();
            foreach (string applWorkeId in workersFromDb)
            {
                List<string> wantedShifts = ApplDbRequestMediator.Instance.GetAllShiftsIdsThatWorkerAskedWithType(
                    applWorkeId, eType.WANTED, startTime, endTime);
                List<string> forbiddenShifts = ApplDbRequestMediator.Instance.GetAllShiftsIdsThatWorkerAskedWithType(
                    applWorkeId, eType.FORBIDDEN, startTime, endTime);
                requests.AddWorkerWithHisRequest(applWorkeId, wantedShifts, forbiddenShifts);
            }

            return requests;
        }

        private void setAllWorkersAndShiftsToAlgoImpl(DateTime startTime, DateTime endTime)
        {
            List<ApplWorker> workersAtDb = ApplDbWorkerMediator.Instance.GetAllWorkers();
            List<ApplShift> shiftsAtDb = ApplDbShiftMediator.Instance.GetShiftsByRange(startTime, endTime);
            List<Worker> algoWorkers = getAllAlgoWorkers(workersAtDb);
            List<Shift> algoShifts = getAllAlgoShifts(shiftsAtDb);
            SharedData.Instance.InitializeWorkersAndShift(algoShifts, algoWorkers);
        }

        private List<Shift> getAllAlgoShifts(List<ApplShift> shiftsAtDb)
        {
            List<Shift> algoShifts = new List<Shift>();
            foreach (ApplShift applShift in shiftsAtDb)
            {
                algoShifts.Add(ApplAlgoObjectConvertor.CreateAlgoShiftFromApplShift(applShift));
            }

            return algoShifts;
        }

        private List<Worker> getAllAlgoWorkers(List<ApplWorker> workersAtDb)
        {
            List<Worker> algoWorkers = new List<Worker>();
            foreach (ApplWorker applWorker in workersAtDb)
            {
                algoWorkers.Add(ApplAlgoObjectConvertor.CreateAlgoWrokerFromAppl(applWorker));
            }

            return algoWorkers;
        }

    }
}
